﻿using System;
using System.Xml;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TrainingCenterSystem.UserManagement;

namespace TrainingCenterSystem.VocabularyManagement
{
    /// <summary>
    /// Represents the options for accessing a collection
    /// </summary>
    public enum CollectionAccess
    {
        Private,
        ReadOnly,
        ReadWrite
    }

    /// <summary>
    /// Represents a vocabulary collection
    /// </summary>
    public class VocabularyCollection
    {
        #region private members
        private string _collectionID;
        private string _collectionName;
        private string _collectionDescription;
        private string _filename;
        private CollectionAccess _access;
        private User _collectionUser;
        private ArrayList _contexts;
        private ArrayList _words;
        #endregion

        #region setters and getters
        /// <summary>
        /// Gets or sets the collection ID
        /// </summary>
        public string CollectionID
        {
            set { _collectionID = value; }
            get { return _collectionID; }
        }

        /// <summary>
        /// Gets or sets the available contexts
        /// </summary>
        public ArrayList Contexts
        {
            get { return _contexts; }
            set { _contexts = value; }
        }

        /// <summary>
        /// Gets the user of the collection
        /// </summary>
        public User CollectionUser
        {
            get { return _collectionUser; }
        }

        /// <summary>
        /// Gets or sets the access tyspe of the collection
        /// </summary>
        public CollectionAccess CollectionAccess
        {
            get { return _access; }
            set { _access = value; }
        }

        /// <summary>
        /// Gets the name of the collection.
        /// </summary>
        public string CollectionName
        {
            get { return _collectionName; }
        }

        /// <summary>
        /// Gets the description of the collection.
        /// </summary>
        public string CollectionDescription
        {
            get { return _collectionDescription; }
        }

        /// <summary>
        /// Gets all words contained in tzhe collection
        /// </summary>
        public ArrayList Words
        {
            get { return _words; }
        }

        public string FileName
        {
            get { return _filename; }
            set 
            { 
                _filename = value;
                this.refreshContexts();
            }
        }
        #endregion

        #region constructor(s)
        /// <summary>
        /// creates a vocabulary collection.
        /// </summary>
        /// <param name="collName">The name of the collection</param>
        /// <param name="collUser">The user who creates the collection</param>
        /// <param name="collAccess">The access type</param>
        public VocabularyCollection(string collName, User collUser, CollectionAccess collAccess)
        {
            _collectionName = collName;
            _collectionUser = collUser;
            _access = collAccess;
            _collectionDescription = null;
            this.initContext();
            this.initContent();
        }

        /// <summary>
        /// creates a vocabulary collection.
        /// </summary>
        /// <param name="collName">The name of the collection</param>
        /// <param name="collUser">The user who creates the collection</param>
        /// <param name="collAccess">The access type</param>
        /// <param name="collDescription">The description of the collection</param>
        public VocabularyCollection(string collName, User collUser, CollectionAccess collAccess, string collDescription)
        {
            _collectionName = collName;
            _collectionUser = collUser;
            _access = collAccess;
            _collectionDescription = collDescription;
            this.initContext();
            this.initContent();
        }
        #endregion

        #region methods
        /// <summary>
        /// Gets all generic words in the collection
        /// </summary>
        /// <returns></returns>
        public List<GenericWord> GetGenerics()
        {
            List<GenericWord> generics = new List<GenericWord>();
            for (int i = 0; i < _words.Count; i++)
            {
                try
                {
                    if ((_words[i] is GenericWord)&&(!((_words[i] is Noun)||(_words[i] is Verb)||(_words[i] is Adjective))))
                        generics.Add((GenericWord)_words[i]);
                }
                catch (Exception ex)
                {
                }
            }

            return generics;
        }

        /// <summary>
        /// Retrieves all words within a specific context
        /// </summary>
        /// <param name="contextName">the name of the context</param>
        /// <returns>word list of type GenericWord</returns>
        public List<GenericWord> GetAllFromContext(string contextName)
        {
            List<GenericWord> wordsInContext = new List<GenericWord>();
            for (int i = 0; i < _words.Count; i++)
            {
                if (((GenericWord)_words[i]).ContextName==contextName)
                    wordsInContext.Add((GenericWord)_words[i]);
            }

            return wordsInContext;
        }

        /// <summary>
        /// Gets all verbs in the collection
        /// </summary>
        /// <returns></returns>
        public List<Verb> GetVerbs()
        {
            List<Verb> verbs= new List<Verb>();
            for (int i=0;i<_words.Count;i++)
            {
                try
                {
                    if (_words[i] is Verb)
                        verbs.Add((Verb)_words[i]);
                }
                catch (Exception ex)
                {
                }
            }

            return verbs;
        }

        /// <summary>
        /// Gets all nouns in the collection
        /// </summary>
        /// <returns></returns>
        public List<Noun> GetNouns()
        {
            List<Noun> nouns = new List<Noun>();
            for (int i = 0; i < _words.Count; i++)
            {
                try
                {
                    if (_words[i] is Noun)
                        nouns.Add((Noun)_words[i]);
                }
                catch (Exception ex)
                {
                }
            }

            return nouns;
        }

        /// <summary>
        /// Gets all adjectives in the collection
        /// </summary>
        /// <returns></returns>
        public List<Adjective> GetAdjectives()
        {
            List<Adjective> adjectives = new List<Adjective>();
            for (int i = 0; i < _words.Count; i++)
            {
                try
                {
                    if (_words[i] is Adjective)
                        adjectives.Add((Adjective)_words[i]);
                }
                catch (Exception ex)
                {
                }
            }
            return adjectives;
        }

        /// <summary>
        /// initializes tzhe contexts of the collection
        /// </summary>
        public void initContext()
        {
            _contexts = new ArrayList();            
        }

        /// <summary>
        /// initializes the content of a collection
        /// </summary>
        public void initContent()
        {
            _words = new ArrayList();            
        }

        /// <summary>
        /// Adds a context to the collection
        /// </summary>
        /// <param name="contextName">the name of the context</param>
        /// <remarks>This method is used while creating an actually new context</remarks>
        public void addContext(string contextName)
        {
            string contextID=(_contexts.Count).ToString();
            _contexts.Add(new VocabularyContext(contextID,contextName,_filename));
        }

        /// <summary>
        /// Adds a context to the collection
        /// </summary>
        /// <param name="context">An instance of thge new context</param>
        /// <remarks> This method is used while reading a collection file</remarks>
        public void addContext(VocabularyContext context)
        {
            _contexts.Add(context);
        }

        /// <summary>
        /// Renames an existing context
        /// </summary>
        /// <param name="contextIndex">the index of the context</param>
        /// <param name="newName">the new name of the context</param>
        public void RenameContext(int contextIndex, string newName)
        {
            ((VocabularyContext)_contexts[contextIndex]).ContextName = newName;
        }

        /// <summary>
        /// Adds a word to the collection
        /// </summary>
        /// <param name="aWord">the word to be added</param>
        public void AddWord(GenericWord aWord)
        {
            aWord.SetWordID(_words.Count.ToString());
            _words.Add(aWord);
        }

        /// <summary>
        /// Updates an existing word within a collection
        /// </summary>
        /// <param name="currentWord">the current word to be updated</param>
        public void UpdateWord(GenericWord currentWord)
        {
            IEnumerator enumerator=_words.GetEnumerator();
            GenericWord aWord=null;
            enumerator.Reset();
            while (enumerator.MoveNext())
            {
                aWord = (GenericWord)enumerator.Current;
                if (aWord.GetWordID() == currentWord.GetWordID())
                {
                    aWord = currentWord;
                    break;
                }
            }
        }

        /// <summary>
        /// Determines whether a specific context exists
        /// </summary>
        /// <param name="contextName">the context name</param>
        /// <returns>true if the context exists</returns>
        public bool ContextExists(string contextName)
        {
            for (int i = 0; i < _contexts.Count; i++)
            {
                VocabularyContext cont = (VocabularyContext)_contexts[i];
                if (cont.ContextName == contextName)
                    return true;
            }
            return false;
        }

        /// <summary>
        /// Determines whether a specific context exists
        /// </summary>
        /// <param name="contextId">the context id</param>
        /// <param name="contextName">the context name</param>
        /// <returns>true if the context exists</returns>
        public bool ContextExists(string contextId, string contextName)
        {
            for (int i = 0; i < _contexts.Count; i++)
            {
                VocabularyContext cont = (VocabularyContext)_contexts[i];
                if ((cont.ContextName==contextName)
                    && (cont.ContextID!=contextId))
                        return true;
            }
            return false;
        }

        /// <summary>
        /// Gets the total number of words in the collection
        /// </summary>
        /// <returns>the total word count</returns>
        public int GetTotalWordCount()
        {            
            return _words.Count;            
        }

        /// <summary>
        /// Gets the amount of contexts in a collection
        /// </summary>
        /// <returns>the amount of contexts</returns>
        public int GetTotalContextCount()
        {           
            return _contexts.Count;
        }

        /// <summary>
        /// Counts the words belonging to a specific context
        /// </summary>
        /// <param name="contextName">the name of the context</param>
        /// <returns>the number of words</returns>
        public int GetWordCountPerContext(string contextName)
        {
            int wordCount = 0;

            // find context
            if (this.ContextExists(contextName))
            {
                for (int i = 0; i < _words.Count; i++)
                {
                    if (((GenericWord)_words[i]).ContextName == contextName)
                        wordCount++;
                }
            }            
            return wordCount;
        }

        /// <summary>
        /// Refreshes all exisating contexts, that is, updates the reference to the owning collection
        /// </summary>
        private void refreshContexts()
        {
            for (int i = 0; i < _contexts.Count; i++)            
                ((VocabularyContext)_contexts[i]).CollectionID = _filename;
        }
        #endregion        
    }
}
